/*
 * list.c
 *
 *  Created on: Jun 10, 2012
 *      Author: Rui Carlos Lorenzetti da Silva
 */

#include <stdlib.h>
#include <string.h>

#include "list.h"

/**
 * Inicializa a lista
 */
void list_init(List *list, void (*destroy)(void *data)) {

	list->size = 0;
	list->destroy = destroy;
	list->head = NULL;
	list->tail = NULL;

	return;

}

/**
 * Destroe a lista
 */
void list_destroy(List *list) {

	void *data;

	/**
	 * Remove cada elemento
	 */
	if(list!=NULL){
		int list_s = list_size(list);
		while (list_s > 0) {
			data = list->head->data;
			if (list_rem_next(list, NULL, (void **) &data)== 0 && list->destroy !=NULL) {
			/**
			 * Chamando a função de destruição do usuário.
			 */
				if(data!=NULL){
					list->destroy(data);
				}

			}
			list_s--;
		}

	}




	return;

}

/**
 * Insere data dentro de list apos o elemento element.
 */

int list_ins_next(List *list, ListElmt *element, const void *data) {

	ListElmt *new_element;

	//Aloca espaço para o proximo elemento
	if ((new_element = (ListElmt *) malloc(sizeof(ListElmt))) == NULL)
		return -1;

	//insere o elemento para a lista

	new_element->data = (void *) data;

	if (element == NULL) {

		//trata da insercao como head
		if (list_size(list) == 0)
			list->tail = new_element;

		new_element->next = list->head;
		list->head = new_element;

	}

	else {

		//trata da insercao para os demais casos
		if (element->next == NULL)
			list->tail = new_element;

		new_element->next = element->next;
		element->next = new_element;

	}

	//adiciona mais um ao contador
	list->size++;

	return 0;

}

/**
 * Remove da lista list, o proximo elemento element, apos data
 */

int list_rem_next(List *list, ListElmt *element, void *data) {

	ListElmt *old_element;

	//Não permite a remoção de lista vazia

	if (list_size(list) == 0)
		return -1;

	//removendo o elemento da lista
	if (element == NULL) {

		//removendo quando o dado é o  head

		data = list->head->data;
		old_element = list->head;
		list->head = list->head->next;

		if (list_size(list) == 1)
			list->tail = NULL;

	}

	else {

		//removendo quando o dado não é o head
		if (element->next == NULL)
			return -1;

		data = element->next->data;
		old_element = element->next;
		element->next = element->next->next;

		if (element->next == NULL)
			list->tail = element;

	}

	//Libera o elemento alocado tipo tipo abstrato de dados
	free(old_element);

	//remove um do tamanho total...

	list->size--;

	return 0;

}
